#include "iomanager.h"

namespace fiber 
{
// FdContext 用于管理文件描述符的事件上下文
// 获取事件对应的上下文（读/写事件分别对应不同的上下文）
EventContext &FdContext::getEveContext(Event event) {
    switch (event) {
        case READ: // 读事件
            return m_read;
        case WRITE: // 写事件
            return m_write;
        default:
            // 断言失败，提示未知事件
            CondPanic(false, "getContext error: unknow event");
    }
    throw std::invalid_argument("getContext invalid event");
}

// 重置事件上下文（清空调度器、协程和回调函数）
void FdContext::resetEveContext(EventContext &ctx) {
    ctx.m_scheduler = nullptr;    // 调度器指针置空
    ctx.m_fiber.reset();          // 协程指针重置
    ctx.m_cb = nullptr;           // 回调函数置空
}

// 触发事件（将事件对应的协程或回调函数加入调度器任务列表）
void FdContext::triggerEvent(Event event) {
    // 断言事件已注册，否则触发 panic
    CondPanic(m_event & event, "event hasn't been registed");
    // 从已注册事件中移除当前触发的事件
    m_event = (Event)(m_event & ~event);
    // 获取事件对应的上下文
    EventContext& ctx = getEveContext(event);
    if (ctx.m_cb) {
        // 若有回调函数，调度回调
        ctx.m_scheduler->scheduler(ctx.m_cb);
    } 
    else {
        // 若无回调，调度关联的协程
        ctx.m_scheduler->scheduler(ctx.m_fiber);
    }
    // 重置上下文（避免重复触发）
    resetEveContext(ctx);
}

// IOManager 构造函数：初始化 epoll、管道，启动调度器
IOManager::IOManager(size_t threads, bool use_caller, const std::string &name) 
: Scheduler(threads, use_caller, name) {
    // 创建 epoll 实例（参数 5000 为历史遗留，无实际意义）
    m_epfd = epoll_create(5000);
    CondPanic(m_epfd > 0, "epoll_create error");

    // 创建管道（用于唤醒阻塞的 epoll_wait）
    int ret = pipe(m_tickleFds);
    CondPanic(ret == 0, "pipe error");  // 管道创建失败则 panic

    // 注册管道读端的可读事件（用于唤醒调度器）
    epoll_event event = {0};
    event.events = EPOLLIN | EPOLLET;  // 可读事件 + 边缘触发
    event.data.fd = m_tickleFds[0];    // 关联管道读端描述符
    // 设置管道读端为非阻塞模式
    ret = fcntl(m_tickleFds[0], F_SETFL, O_NONBLOCK);
    CondPanic(ret == 0, "set fd nonblock error");
    // 将管道读端添加到 epoll 监控
    ret = epoll_ctl(m_epfd, EPOLL_CTL_ADD, m_tickleFds[0], &event);
    CondPanic(ret == 0, "epoll_ctl error");

    // 初始化文件描述符上下文数组（初始大小 32）
    contextResize(32);

    // 启动调度器（开始协程调度）
    start();
}

// 析构函数：停止调度器，释放资源
IOManager::~IOManager() {
    stop();  // 停止调度器
    close(m_epfd);               // 关闭 epoll 实例
    close(m_tickleFds[0]);       // 关闭管道读端
    close(m_tickleFds[1]);       // 关闭管道写端

    // 释放所有 FdContext 资源
    for (size_t i = 0; i < m_fdContexts.size(); i++) {
        if (m_fdContexts[i]) {
            delete m_fdContexts[i];
        }
    }
}

// 添加 IO 事件（读/写）
// 参数：文件描述符、事件类型、回调函数（可选，默认使用当前协程）
int IOManager::addEvent(int fd, Event event, std::function<void()> cb) {
    FdContext* fd_ctx = nullptr;
    RWMutex::ReadLock lock(m_rwmutex);  // 读锁：检查是否已有上下文
    
    // 若 fd 在当前数组范围内，直接获取上下文
    if ((int)m_fdContexts.size() > fd) {
        fd_ctx = m_fdContexts[fd];
        lock.unlock();  // 提前释放读锁
    } 
    else {
        lock.unlock();  // 释放读锁
        RWMutex::WriteLock lock2(m_rwmutex);  // 写锁：扩容数组
        contextResize(fd * 1.5);  // 扩容至 fd 的 1.5 倍（避免频繁扩容）
        fd_ctx = m_fdContexts[fd];
    }

    // 加锁保护 FdContext 操作
    Mutex::Lock ctxLock(fd_ctx->m_mutex);
    // 断言事件未重复注册
    CondPanic(!(fd_ctx->m_event & event), "addevent error, fd = " + fd);

    // 确定 epoll_ctl 操作类型（新增或修改）
    int op = static_cast<int>(fd_ctx->m_event) ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
    epoll_event epevent = {0};
    epevent.events = EPOLLET | static_cast<EPOLL_EVENTS>(fd_ctx->m_event) 
                    | static_cast<EPOLL_EVENTS>(event);  // 边缘触发 + 已有事件 + 新事件
    epevent.data.ptr = fd_ctx;  // 关联 FdContext 指针

    // 执行 epoll_ctl 操作（添加/修改事件）
    int ret = epoll_ctl(m_epfd, op, fd, &epevent);
    if (ret) {
        std::cout << "addevent: epoll ctl error" << std::endl;
        return -1;
    }
    // 待处理事件计数 +1
    ++m_pendingEventCnt;

    // 更新 FdContext 的事件集
    fd_ctx->m_event = static_cast<Event>(fd_ctx->m_event | event);
    // 获取事件对应的上下文
    EventContext& event_ctx = fd_ctx->getEveContext(event);
    // 断言上下文未被占用
    CondPanic(!event_ctx.m_scheduler && !event_ctx.m_fiber && !event_ctx.m_cb, "event_ctx is nullptr");

    // 设置上下文的调度器
    event_ctx.m_scheduler = Scheduler::GetThis();
    if (cb) {
        // 若有回调函数，保存回调
        event_ctx.m_cb.swap(cb);
    } 
    else {
        // 若无回调，关联当前协程（后续事件触发时恢复该协程）
        event_ctx.m_fiber = Fiber::GetThis();
        // 断言当前协程状态非运行中（避免错误）
        CondPanic(event_ctx.m_fiber->getState() == Fiber::State::RUNNING,
                "state=" + std::to_string(static_cast<int>(event_ctx.m_fiber->getState())));
    }
    std::cout << "add event success, fd = " << fd << std::endl;
    return 0;
}

// 删除 IO 事件（删除前不触发事件）
bool IOManager::delEvent(int fd, Event event) {
    RWMutex::ReadLock lock(m_rwmutex);
    // 若 fd 超出上下文数组范围，直接返回失败
    if ((int)m_fdContexts.size() <= fd) {
        return false;
    }

    FdContext* fd_ctx = m_fdContexts[fd];
    lock.unlock();

    Mutex::Lock ctxLock(fd_ctx->m_mutex);
    // 若事件未注册，返回失败
    if (!(fd_ctx->m_event & event)) {
        return false;
    }

    // 计算剩余事件（移除目标事件后）
    Event new_events = (Event)(fd_ctx->m_event & ~event);
    // 确定 epoll_ctl 操作类型（修改或删除）
    int op = static_cast<int>(new_events) ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
    epoll_event epevent;
    epevent.events = EPOLLET | static_cast<EPOLL_EVENTS>(new_events);  // 边缘触发 + 剩余事件
    epevent.data.ptr = fd_ctx;

    // 执行 epoll_ctl 操作（修改/删除事件）
    int ret = epoll_ctl(m_epfd, op, fd, &epevent);
    if (ret) {
        std::cout << "delevent: epoll_ctl error" << std::endl;
        return false;
    }
    // 待处理事件计数 -1
    --m_pendingEventCnt;
    // 更新事件集并重置上下文
    fd_ctx->m_event = new_events;
    EventContext &event_ctx = fd_ctx->getEveContext(event);
    fd_ctx->resetEveContext(event_ctx);
    return true;
}

// 取消 IO 事件（取消前会触发事件）
bool IOManager::cancelEvent(int fd, Event event) {
    RWMutex::ReadLock lock(m_rwmutex);
    if ((int)m_fdContexts.size() <= fd) {
        return false;
    }
    FdContext *fd_ctx = m_fdContexts[fd];
    lock.unlock();

    Mutex::Lock ctxLock(fd_ctx->m_mutex);
    if (!(fd_ctx->m_event & event)) {
        return false;
    }

    // 计算剩余事件
    Event new_events = (Event)(fd_ctx->m_event & ~event);
    int op = static_cast<int>(new_events) ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
    epoll_event epevent = {0};
    epevent.events = EPOLLET | static_cast<EPOLL_EVENTS>(new_events);
    epevent.data.ptr = fd_ctx;

    // 执行 epoll_ctl 操作
    int ret = epoll_ctl(m_epfd, op, fd, &epevent);
    if (ret) {
        std::cout << "delevent: epoll_ctl error" << std::endl;
        return false;
    }
    // 触发事件（在删除前执行回调或恢复协程）
    fd_ctx->triggerEvent(event);
    // 待处理事件计数 -1
    --m_pendingEventCnt;
    return true;
}

// 取消 fd 上的所有事件（取消前触发所有已注册事件）
bool IOManager::cancelAll(int fd) {
    RWMutex::ReadLock lock(m_rwmutex);
    if ((int)m_fdContexts.size() <= fd) {
        return false;
    }
    FdContext *fd_ctx = m_fdContexts[fd];
    lock.unlock();

    Mutex::Lock ctxLock(fd_ctx->m_mutex);
    if (!fd_ctx->m_event) {  // 无注册事件，直接返回
        return false;
    }

    // 从 epoll 中删除该 fd 的所有事件
    int op = EPOLL_CTL_DEL;
    epoll_event epevent = {0};
    epevent.events = 0;
    epevent.data.ptr = fd_ctx;
    int ret = epoll_ctl(m_epfd, op, fd, &epevent);
    if (ret) {
        std::cout << "delevent: epoll_ctl error" << std::endl;
        return false;
    }

    // 触发所有已注册事件
    if (fd_ctx->m_event & READ) {
        fd_ctx->triggerEvent(READ);
        --m_pendingEventCnt;
    }
    if (fd_ctx->m_event & WRITE) {
        fd_ctx->triggerEvent(WRITE);
        --m_pendingEventCnt;
    }
    // 断言所有事件已清除
    CondPanic(fd_ctx->m_event == 0, "fd not totally clear");
    return true;
}

// 获取当前 IOManager 实例（从调度器中动态转换）
IOManager *IOManager::GetThis() { 
    return dynamic_cast<IOManager*>(Scheduler::GetThis()); 
    // 调度器是IO调度器的话就返回，不是就返回nullptr
}

// 唤醒调度器（向管道写数据，使 epoll_wait 退出阻塞）
void IOManager::tickle() {
    if (!isHasIdleThreads()) {  // 无空闲线程时无需唤醒
        return;
    }
    // 向管道写一个字节（内容无意义，仅用于唤醒）
    int rt = write(m_tickleFds[1], "T", 1);
    CondPanic(rt == 1, "write pipe error");  // 写入失败则 panic
}

// 空闲协程：阻塞等待 IO 事件或定时器事件，处理就绪事件
void IOManager::idle() {
    const uint64_t MAX_EVENTS = 256;  // 一次最多处理 256 个事件
    epoll_event* events = new epoll_event[MAX_EVENTS]();
    // 智能指针管理事件数组（自动释放）
    std::shared_ptr<epoll_event> shared_events(events, [](epoll_event *ptr) { delete[] ptr; });

    while (true) {
        // 获取下一个定时器超时时间，检查是否需要停止
        uint64_t next_timeout = 0;
        if (stopping(next_timeout)) {
            std::cout << "name=" << getName() << "idle stopping exit";
            break;
        }

        // 阻塞等待事件（最长阻塞 next_timeout 毫秒）
        int ret = 0;
        do {
            static const int MAX_TIMEOUT = 5000;  // 最大超时时间 5 秒

            // 限制超时时间（避免过大）
            if (next_timeout != ~0ull) {
                next_timeout = std::min((int)next_timeout, MAX_TIMEOUT);
            } else {
                next_timeout = MAX_TIMEOUT;
            }
            // 等待事件就绪
            ret = epoll_wait(m_epfd, events, MAX_EVENTS, (int)next_timeout);
            if (ret < 0) {
                if (errno == EINTR) {  // 被信号中断，重试
                    continue;
                }
                std::cout << "epoll_wait [" << m_epfd << "] errno,err: " << errno << std::endl;
                break;
            } 
            else {
                break;
            }
        } while (true);

        // 处理所有超时的定时器任务
        std::vector<std::function<void()>> cbs;
        listExpiredCb(cbs);  // 收集超时回调
        if (!cbs.empty()) {
            for (const auto &cb : cbs) {
                scheduler(cb);  // 调度回调执行
            }
            cbs.clear();
        }

        // 处理就绪的 IO 事件
        for (int i = 0; i < ret; i++) {
            epoll_event &event = events[i];
            // 若为管道读事件（唤醒信号），读取数据并忽略
            if (event.data.fd == m_tickleFds[0]) {
                uint8_t dummy[256];
                // 读取所有数据（边缘触发需一次性读完）
                while (read(m_tickleFds[0], dummy, sizeof(dummy)) > 0)
                ;
                continue;
            }

            // 从事件中获取 FdContext
            FdContext* fd_ctx = (FdContext*)event.data.ptr;
            Mutex::Lock lock(fd_ctx->m_mutex);

            // 处理错误事件或挂起事件（对端关闭）
            if (event.events & (EPOLLERR | EPOLLHUP)) {
                std::cout << "error events" << std::endl;
                // 强制触发读/写事件（根据已注册的事件类型）
                event.events |= (EPOLLIN | EPOLLOUT) 
                            & static_cast<EPOLL_EVENTS>(fd_ctx->m_event);
            }

            // 解析实际就绪的事件类型（读/写）
            int real_events = NONE;
            if (event.events & EPOLLIN) {
                real_events |= READ;
            }
            if (event.events & EPOLLOUT) {
                real_events |= WRITE;
            }

            // 若就绪事件与注册事件无交集，忽略
            if ((fd_ctx->m_event & real_events) == NONE) {
                continue;
            }

            // 计算剩余未就绪的事件，更新 epoll 监控
            int left_events = (fd_ctx->m_event & ~real_events);
            int op = static_cast<int>(left_events) ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
            event.events = EPOLLET | static_cast<EPOLL_EVENTS>(left_events);

            // 更新 epoll 事件
            int ret2 = epoll_ctl(m_epfd, op, fd_ctx->m_fd, &event);
            if (ret2) {
                std::cout << "epoll_wait [" << m_epfd << "] errno,err: " << errno << std::endl;
                continue;
            }

            // 触发就绪事件（调度回调或协程）
            if (real_events & READ) {
                fd_ctx->triggerEvent(READ);
                --m_pendingEventCnt;
            }
            if (real_events & WRITE) {
                fd_ctx->triggerEvent(WRITE);
                --m_pendingEventCnt;
            }
        }

        // 空闲协程让出 CPU，调度器处理其他任务
        Fiber::ptr cur = Fiber::GetThis();
        auto raw_ptr = cur.get();
        cur.reset();  // 释放智能指针引用
        raw_ptr->yield();  // 协程yield
    }
}

// 检查调度器是否需要停止（无超时定时器且无待处理IO事件）
bool IOManager::stopping() {
    uint64_t timeout = 0;
    return stopping(timeout);
}

bool IOManager::stopping(uint64_t& timeout) {
    timeout = getNextTimer();  // 获取下一个定时器超时时间
    // 停止条件：无超时定时器 + 无待处理IO事件 + 调度器已停止
    return timeout == ~0ull && m_pendingEventCnt == 0 && Scheduler::stopping();
}

// 扩容文件描述符上下文数组
void IOManager::contextResize(size_t size) {
    m_fdContexts.resize(size);
    // 初始化新扩容的元素
    for (size_t i = 0; i < m_fdContexts.size(); i++) {
        if (!m_fdContexts[i]) {
            m_fdContexts[i] = new FdContext;
            m_fdContexts[i]->m_fd = i;  // 上下文关联的fd
        }
    }
}

// 定时器插入到头部时触发（唤醒调度器处理）
void IOManager::OnTimerInsertedAtFront() { 
    tickle(); 
}

}  // namespace fiber